package com.c2b.algorithm.leetcode.base;

/**
 * <a href="https://leetcode.cn/problems/find-peak-element/description/?envType=study-plan-v2&envId=top-interview-150">寻找峰值(Find Peak Element)</a>
 * <p>峰值元素是指其值严格大于左右相邻值的元素。</p>
 * <p>给你一个整数数组 nums，找到峰值元素并返回其索引。数组可能包含多个峰值，在这种情况下，返回 任何一个峰值 所在位置即可。</p>
 * <p>你可以假设 nums[-1] = nums[n] = -∞ 。</p>
 * <p>你必须实现时间复杂度为 O(log n) 的算法来解决此问题。</p>
 *
 * <p>
 * <b>示例：</b>
 * <pre>
 * 示例 1：
 *      输入：nums = [1,2,3,1]
 *      输出：2
 *      解释：3 是峰值元素，你的函数应该返回其索引 2。
 *
 * 示例 2：
 *      输入：nums = [1,2,1,3,5,6,4]
 *      输出：1 或 5
 *      解释：你的函数可以返回索引 1，其峰值元素为 2；
 *              或者返回索引 5， 其峰值元素为 6。
 * </pre>
 * </p>
 *
 * <p>
 * <b>提示：</b>
 *  <ul>
 *      <li>1 <= nums.length <= 1000</li>
 *      <li>-2^31 <= nums[i] <= 2^31 - 1</li>
 *      <li>对于所有有效的 i 都有 nums[i] != nums[i + 1]</li>
 *  </ul>
 * </p>
 *
 * @author c2b
 * @since 2023/10/19 14:03
 */
public class LC0162FindPeakElement_M {

    static class Solution {
        public int findPeakElement(int[] nums) {
            if (nums.length <= 1) {
                return 0;
            }
            int left = 0;
            int right = nums.length - 1;
            int mid;
            while (left <= right) {
                mid = left + ((right - left) >> 1);
                if (mid == 0) {
                    // 1.如果在左边界
                    if (nums[mid] > nums[mid + 1]) {
                        return mid;
                    } else {
                        left = mid + 1;
                    }
                } else if (mid == nums.length - 1) {
                    // 2.如果在右边界
                    if (nums[mid] > nums[mid - 1]) {
                        return mid;
                    } else {
                        right = mid - 1;
                    }
                } else {
                    // 3.如果在非边界
                    if ((nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1])) {
                        // 位于峰值。直接返回
                        return mid;
                    } else if (nums[mid] > nums[mid - 1] && nums[mid] < nums[mid + 1]) {
                        // mid 在上升趋势的中间
                        left = mid + 1;
                    } else if ((nums[mid] < nums[mid - 1] && nums[mid] > nums[mid + 1])) {
                        // mid 在下降趋势的中间
                        right = mid - 1;
                    } else {
                        // 位于谷底。 left = mid +1 或者 right = mid -1
                        left = mid + 1;
                    }
                }
            }
            return -1;
        }

        public static void main(String[] args) {
            Solution solution = new Solution();
            //System.out.println(solution.findPeakElement(new int[]{1, 2, 3, 1}));
            //System.out.println(solution.findPeakElement(new int[]{1, 2, 1, 3, 5, 6, 4}));
            //System.out.println(solution.findPeakElement(new int[]{1}));
            //System.out.println(solution.findPeakElement(new int[]{1, 2}));
            System.out.println(solution.findPeakElement(new int[]{3, 1, 2}));
        }
    }
}
